/*
 * Copyright (C) 2000-2005 Philips Electronics N.V.
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or 
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; see the file gnu_license.txt.  If not, write to
 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  
 * 
 */
#include <stdio.h>
#include <string.h>
#include <front/print_support.h>
#include <front/flags.h>
#include <front/text.h>
#include <front/error.h>

#include "fe_flags.h"
#include "cpp.h"
#include "errors.h"

#define BOOLval(b) ((b) ? "TRUE" : "FALSE")

char *infile = "stdin";
Bool override_infile = FALSE;
Bool trace_rewrite = FALSE;

Bool have_longlong = FALSE;
Bool have_restrict = FALSE;

static int set_std     (int argc, char **argv);
static int set_c99     (int argc, char **argv);
static int set_infile  (int argc, char **argv);
static int set_error   (int argc, char **argv);
static int set_gcc_error(int argc, char **argv);
static int error_list  (int argc, char **argv);

/* Information describing command switches */
fe_cli_flag cfront_flags[] = {
  { "-finput-file", NULL, &set_infile,    "-finput-file <file>", { "set input filename" } },
  { "-pretty",      &Front_pretty, NULL,  "-pretty",             { "pretty print C output" } ,},
  { "-X.*",         NULL, set_error,      "-X<error> [error|warning|disabled]",  { "change the relevance of an error message" } },
  { "-list-errors", NULL, error_list,     "-list-errors",        { "list all errors and their mode" } },

  /* C99 compatibility options */
  { "-longlong",    &have_longlong, NULL, "-longlong",           { "enable the long long types" } },
  { "-restrictptr", &have_restrict, NULL, "-restrictptr",        { "enable restricted pointers" } },

  { "-c99",         &have_longlong, NULL, DFLT_NAME,             { "enable all supported c99 features" } },
  { "-c99",         &have_restrict, NULL, DFLT_NAME,             { "enable all supported c99 features" } },
  { "-c99",         NULL, set_c99,        DFLT_NAME,             { "enable all supported c99 features" } },
};

int num_cfront_flags = sizeof(cfront_flags)/sizeof(cfront_flags[0]);

/* flags below are introduced to resemble the gcc arguments more */
fe_cli_flag cfront_gcc_flags[] = {
  /*below: don't match anything like -Wl,option */
  { "-W[^,]*=.*",       NULL,           set_gcc_error,  "-W<err>=<mode>",      { "change the relevance of an error message", "mode is one of {error,warning,disabled}" } },
  { "-list-errors",     NULL,           error_list,     "-list-errors",        { "list all errors and their mode" } },
  { "-std=.*",          NULL,           set_std,        "-std=<standard>",     { "determines the language standard", "standard is one of {c89,c99,gnu89,gnu99}" } },

  /* Options to switch on specific features. */

  { "-flonglong",       &have_longlong, NULL,           "-f[no-]longlong",     { "enable the long long types", "@feature" } },
  { "-frestrictptr",    &have_restrict, NULL,           "-f[no-]restrictptr",  { "enable restricted pointers", "@feature" } },
#if 0
  /* Options to switch off specific features. */

  { "-fno-longlong",    &have_longlong, fe_reset_flag,  DFLT_NAME,             { NULL } },
  { "-fno-restrictptr", &have_restrict, fe_reset_flag,  DFLT_NAME,             { NULL } },

  /* Put -fAll or -fNone before any -f or -fno's on the command line to allow the latter to override. */

  { "-fAll",  &have_longlong, NULL,          DFLT_NAME, { "enable all boolean -f<feature> options, except -fno-<feature> options following on command line" } },
  { "-fAll",  &have_restrict, NULL,          DFLT_NAME, { "enable all boolean -f<feature> options, except -fno-<feature> options following on command line" } },

  { "-fNone", &have_longlong, fe_reset_flag, DFLT_NAME, { "disable all boolean -f<feature> options, except -f<feature> options following on command line" } },
  { "-fNone", &have_restrict, fe_reset_flag, DFLT_NAME, { "disable all boolean -f<feature> options, except -f<feature> options following on command line" } },
#endif
};
int num_cfront_gcc_flags = sizeof(cfront_gcc_flags)/sizeof(cfront_gcc_flags[0]);

static int
set_std(int argc, char *argv[])
{
  char *a = &argv[0][5];
  argc = argc;
  if(*a == '\0') {
    fe_error ("Missing language standard");
  }
  else if (!strcmp(a, "c89")) {
  }
  else if (!strcmp(a, "c99")) {
    have_longlong = TRUE;
    have_restrict = TRUE;
    set_c99 (argc, argv);
  }
  else if (!strcmp(a, "gnu89")) {
  }
  else if (!strcmp(a, "gnu99")) {
    have_longlong = TRUE;
    have_restrict = TRUE;
    set_c99 (argc, argv);
  }
  else {
    fe_error ("Unsupported language standard '%s'", a);
  }
  return 0;
}

static int
set_c99 (int argc, char **argv)
{
  NOT_USED(argc);
  NOT_USED(argv);
  CPP_c99();
  return 0;
}

static int
error_list (int argc, char **argv)
{
  NOT_USED(argc);
  NOT_USED(argv);
  cfront_predefined_list_options();
  cfront_list_options();
  return 0;
}

static int
set_error (int argc, char **argv)
{ if (argc < 2) {
    FrontError (TRUE, "Missing error mode");
  } else {
    cfront_parse_option (argv[0]+2, argv[1]);
  }
  return 1;
}

static int
set_gcc_error (int argc, char *argv[])
{
  char *msg  = fe_strdup(argv[0]);
  char *mode = index(msg, '=');

  argc = argc;

  assert(mode); /*should find '=', was specified in regexp*/
  
  *mode++ = '\0'; /*terminate msg, skip '=' */
  if (!strlen(mode)) {
     fe_error ("Missing error mode for error '%s'", msg+2);
  } else {
    cfront_parse_option (msg+2, mode);
  }
  return 0;
}

static int
set_infile (int argc, char **argv)
{ if (argc < 2) {
    FrontError (TRUE, "Missing input file");
  } else {
    infile = argv[1];
    override_infile = TRUE;
  }
  return 1;
}

void cfront_dump_gcc_flags (void) {
  fprintf (stderr, "have_longlong    = %s.\n", BOOLval (have_longlong));
  fprintf (stderr, "have_restrict    = %s.\n", BOOLval (have_restrict));
}
